﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using MSWebBroswerEx.ComPlusDrawing;
namespace MSWebBrowserEx
{
    public class WebBrowserEx : IDisposable
    {
        string _blank = "about:Blank";
        System.Windows.Forms.Timer _tmer = new System.Windows.Forms.Timer();
        Uri _url = null;
        int _wbHeight = 0;
        int _wbWidth = 0;
        int _wbDocumentTextLength = 0;
        int _counter = 0;
        /// <summary>
        /// 用于标识每次打开网页的Key
        /// </summary>
        private string _key = string.Empty;
        private int _internval = 3000;   //默认每个循环为5秒
        /// <summary>
        /// 每次循环使用的次数
        /// </summary>
        public int Internval
        {
            set
            {
                _internval = value;
            }
        }
        private int _maxTimes = 20;
        /// <summary>
        /// 等待多少个Internval 循环后，默认网页已经加载完
        /// </summary>
        public int MaxTimes
        {
            set
            {
                _maxTimes = value;
            }
        }

        public delegate void DocumentCompletedEventHandler(string key, string htmlString ,Bitmap img );
        public event DocumentCompletedEventHandler DocumentCompletedEvent;

        public delegate void DocumentStatusChangedEventHandler(string key ,WebBrowserReadyState currentStatus );
        public event DocumentStatusChangedEventHandler DocumentStatusChangedEvent;

        public delegate void DocumentTitleShownEventHandler(string key, string title);
        public event DocumentTitleShownEventHandler DocumentTitleShownEvent;

        public delegate void MemoryOverflowEventHandler(string key );
        public event MemoryOverflowEventHandler MemoryOverflowEvent;

        public delegate void ErrorEventHandler(string key, string detail);
        public event ErrorEventHandler ErrorEvent;

        WebBrowser _bo = null;
        public string Key
        {
            get
            {
                return _key;
            }
        }
        public WebBrowserEx(WebBrowser wb = null )
        {
            _bo = wb == null ? new WebBrowser() : wb;
            _bo.ScriptErrorsSuppressed = true;
            _bo.ScrollBarsEnabled = false;
            _tmer.Interval = this._internval;
            _tmer.Tick += tmer_Tick;
            _bo.DocumentTitleChanged += bo_DocumentTitleChanged;
            _bo.DocumentCompleted += bo_DocumentCompleted;
            
        }

        public void OpenUrl(string url ,string key )
        {
            //Reset timer parameters
            this.Stop();
            _key = key;
            try
            {
                _url = new Uri(url);
            }
            catch(Exception ex )
            {
                if (ErrorEvent != null)
                {
                    //解发错误事件
                    string tmp = this.Key;
                    this._key = string.Empty;
                    ErrorEvent(tmp, string.Format("Invalid URI \"{0}\"" ,url ));
                    return;
                }
            }
            if (!string.IsNullOrEmpty(_url.OriginalString ))
            {
                _bo.Navigate( _url );
                //触发事件
                TriggerDocumentStatusChangedEvent(WebBrowserReadyState.Loading);
            }
            else
            {
                string tmp = this.Key;
                this._key = string.Empty;
                if (ErrorEvent != null )
                {
                    ErrorEvent(tmp, string.Format("Empty url parameter for OpenUrl Invoker whick key is \"{0}\".", this._key));
                }
                else
                {
                    throw (new Exception(string.Format("Empty url parameter for OpenUrl Invoker whick key is \"{0}\"." ,this._key )));
                }
            }
        }

        public void Stop()
        {
            _bo.Stop();
            this._key = string.Empty;
            ResetForNavigating(true);
        }
        #region Private Methods
        void bo_DocumentTitleChanged(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            if (!string.IsNullOrWhiteSpace(_bo.DocumentTitle ) && DocumentTitleShownEvent != null)
            {
                DocumentTitleShownEvent(this.Key, _bo.DocumentTitle);
            }
        }
        void bo_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            //this.wb.Document.Window.Resize += new System.Windows.Forms.HtmlElementEventHandler(this.wb_WindowResize);
            //if (bo.ReadyState == WebBrowserReadyState.Complete)
            //{
                //轮循Size是否有变化
                if (_tmer.Tag == null )
                {
                    _tmer.Tag = "Started";
                    _tmer.Interval = this._internval;
                    _tmer.Start();
                }
                else
                {
                    ResetForNavigating(false );
                }
            //}
        }
        void TriggerDocumentStatusChangedEvent(WebBrowserReadyState currentStatus )
        {
            if (DocumentStatusChangedEvent != null )
            {
                DocumentStatusChangedEvent(this.Key, currentStatus);
            }
        }
        
        void tmer_Tick(object sender, EventArgs e)
        {
            //throw new NotImplementedException();
            if (_counter >= _maxTimes)
            {
                this._tmer.Tag = null;
                this._tmer.Stop();
                
                //超过3次没有没有变化时，表示页面已经加载完//触发事件
                /**
                HtmlElementCollection elCol = this._bo.Document.All;
                StringBuilder sb = new StringBuilder();
                foreach (HtmlElement el in elCol)
                {
                    if (el.Parent == null)
                    {
                        sb.Append(el.OuterHtml);
                    }
                }
                 */
                //获取图片
                this._bo.Width += 16;
                Snapshot snap = new Snapshot();
                Bitmap bitmap = snap.TakeSnapshot(_bo.ActiveXInstance, new Rectangle(0, 0, _wbWidth + 16, _wbHeight));
                //清空当前的Key
                string ky = this.Key;
                this._key = string.Empty;
                if (bitmap == null )
                {
                    if (MemoryOverflowEvent != null )
                    {
                        MemoryOverflowEvent(ky );
                    }
                }
                else
                {
                    DocumentCompletedEvent(ky , string.Empty, bitmap);
                }
            }
            else
            {
                ResetWebBroswerSize();
            }
        }

        void ResetWebBroswerSize()
        {
            if (_bo.Document.Body != null)
            {
                int hei = _bo.Document.Body.Parent.ScrollRectangle.Height;
                int wid = _bo.Document.Body.Parent.ScrollRectangle.Width;
                if (hei > _wbHeight || wid > _wbWidth )
                {
                    _wbHeight = hei;
                    _wbWidth = wid;
                    //重新设置临时变量
                    this._bo.Height = hei;
                    this._bo.Width = wid;
                    //重置计时器
                    _counter = 0;
                    TriggerDocumentStatusChangedEvent(WebBrowserReadyState.Interactive);
                }
                //else if (_bo.DocumentText.Length > _wbDocumentTextLength)
                //{
                //    _wbDocumentTextLength = _bo.DocumentText.Length;
                //    //重置计时器
                //    _counter = 0;
                //    TriggerDocumentStatusChangedEvent(WebBrowserReadyState.Interactive);
                //}
                else
                {
                    _counter++;
                }
            }
        }

        void ResetForNavigating(bool needStopTimer )
        {
            this._wbWidth = 0;
            this._wbHeight = 0;
            this._bo.Height = 50;
            this._bo.Width = 50;
            this._wbDocumentTextLength = 0;

            if (needStopTimer)
            {
                this._tmer.Stop();
                this._tmer.Tag = null;
                _bo.Url = new Uri(_blank);
            }
            this._counter = 0;
        }
        #endregion

        public void Dispose()
        {
            //throw new NotImplementedException();
            this._bo.Dispose();
            this._bo = null;
        }
    }
}
